/*
共享内存与消息队列
*/

#include "process.h"
#include "cJSON.h"

/*
    功能：创建关键字
    参数：无
    返回值：关键字
*/
int creat_key()
{
    key_t key = ftok("/home/hq/key", 'a'); // 生成关键字
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    return key;
}

/*
    功能：创建共享内存，建立映射关系
    参数：shmid：共享内存标识符
    返回值：映射后的地址
*/
std_node_t *creat_shm(int *shmid)
{
    int key = creat_key();                                   // 创建关键字
    *shmid = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666); // 创建共享内存
    if (*shmid < 0)                                          // 创建共享内存失败
    {
        if (errno == EEXIST) // 如果已经创建共享内存
        {
            *shmid = shmget(key, SIZE, 0666); // 直接打开共享内存
        }
        else
        {
            perror("shmget err");
            return NULL;
        }
    }
    std_node_t *shmaddr = shmat(*shmid, NULL, 0); // 建立映射关系
    if (shmaddr == (std_node_t *)-1)
    {
        perror("shmat err");
        return NULL;
    }
    return shmaddr;
}

/*
    功能：创建消息队列
    参数：无
    返回值：消息队列标识符
*/
int creat_msg()
{
    int key = creat_key();                                // 创建关键字
    int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666); // 创建消息队列
    if (msgid <= 0)
    {
        if (msgid == 0) // 消息队列已存在
        {
            msgctl(0, IPC_RMID, NULL);
            msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
        }
        else if (errno == EEXIST) // 消息队列已存在
        {
            msgid = msgget(key, 0666);
        }
        else // 创建消息队列失败
        {
            perror("msgget err");
            return -1;
        }
    }
    return msgid; // 创建消息队列成功
}

/*
    功能：添加并发送消息
    参数：int msgid：消息队列标识符
         long type：消息类型
         std_node_t *object：消息正文
    返回值：成功返回0，失败返回-1
*/
int send_msg(int msgid, long type, std_node_t *object)
{
    msg_t msg = {0};
    msg.mtype = type;
    memcpy(&msg.data, object, sizeof(std_node_t));
    int ret = msgsnd(msgid, &msg, sizeof(msg_t) - sizeof(long), 0);
    return ret;
}

/*
    功能：接收消息
    参数：int msgid：消息队列标识符
         msg_t *msg：接收消息的结构体指针
         long type：消息类型
         int flag：接收消息的方式
            0：阻塞接收
            IPC_NOWAIT：非阻塞接收
    返回值：成功返回消息长度，失败返回-1
*/
int recv_msg(int msgid, msg_t *msg, long type, int flag)
{
    int len = msgrcv(msgid, msg, sizeof(msg_t) - sizeof(long), type, flag);
    return len;
}